﻿using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;

namespace AppFuscator.MapDecoder
{
    internal class Parser
    {
        public static IEnumerable<string> ParseAllText(string s) //парсю  "методы"  и добавляю их в список
        {
            var list = new List<string>();
            const string pattern = @"[\w\.\,_<>&\[\]\`\/\(]+\([\w\.\,_ <>&\[\]\`\/\(]*\)";
            var regex = new Regex(pattern);
            var match = regex.Match(s);
            while (match.Success)
            {
                var line = match.Value.Trim(' ');
                list.Add(line);
                match = match.NextMatch();
            }
            return list;
        }

        public static MethodInfo? ParseMethod(string s) //парсю в переданном методе его параметры, тип и название метода
        {
            s = s.Trim(' ');
            var structMethod = new MethodInfo();
            structMethod.FullMethodName = s;
            const string patternParameter = @"(?<=\()[\w\.\, _<>&\[\]\`]+(?=\))"; //выделяю всю фразу в скобках.
            var regex = new Regex(patternParameter);
            string[] separator = new string[] { "," };
            string[] spl = regex.Match(s).Value.Split(separator, StringSplitOptions.RemoveEmptyEntries);

            if (spl.Length > 0) //если есть параметры, то заношу каждый по отдельности в массив параметров.
            {
                int i = 0;
                structMethod.Parameters = new string[spl.Length];
                foreach (var splited in spl) //splited - выделенный кусок параметра с именем, до запятой (System.Int32 myInt)
                {
                    var str = splited.Split(' ');
                    string result = ConvertStandartTypeParametr(str[0]);
                    structMethod.Parameters[i++] = result;
                    //var tmp = s.Split(' '); //отделённые параметр и его имя, в обфускаторе имени не будет, но про запас. (System.Int32 + myInt)
                }
            }
            const string patternTypeName = @"[\w\`\._<>&]+(?=\.[\w\`]+\()"; //поиск типов как слов отделённых справа точкой, затем любым кол-вом символов, и скобкой. word.xxx(xxx);
            regex = new Regex(patternTypeName);
            var parsedNameType = regex.Match(s).Value.TrimEnd('.'); //MyApp.MyClass.MyNested..ctor() -> MyApp.MyClass.MyNested
            structMethod.FullTypeName = parsedNameType;
            var startIndex = parsedNameType.Length + 1;
            var length = s.IndexOf('(') - parsedNameType.Length - 1;
            if (length < 0)
                return null; //если не будет найден метод, то вернёт null
            if (parsedNameType.Length == 0)
            {
                var parsedNameMethod = s.Substring(0, s.IndexOf('('));
                structMethod.MethodName = parsedNameMethod;
                structMethod.FullTypeName = "<Module>";
            }
            else
            {
                var parsedNameMethod = s.Substring(startIndex, length); //MyApp.MyClass.MyNested..ctor() -> .ctor()
                structMethod.MethodName = parsedNameMethod;
            }
            return structMethod;
        }

        private static string ConvertStandartTypeParametr(string s)
        {
            string spl = "";
            if (s.IndexOf("[]") > 0) //Если есть скобки
            {
                s = s.Split('[')[0]; //то вырезать кусок без скобок
                spl = "[]";
            }
            s = s.ToLower();
            if (s == "byte") return "Byte" + spl;
            if (s == "sbyte") return "SByte" + spl;
            if (s == "int") return "Int32" + spl;
            if (s == "uint") return "UInt32" + spl;
            if (s == "short") return "Int16" + spl;
            if (s == "ushort") return "UInt16" + spl;
            if (s == "long") return "Int64" + spl;
            if (s == "ulong") return "UInt64" + spl;
            if (s == "float") return "Single" + spl;
            if (s == "double") return "Double" + spl;
            if (s == "char") return "Char" + spl;
            if (s == "bool") return "Boolean" + spl;
            if (s == "object") return "Object" + spl;
            if (s == "string") return "String" + spl;
            if (s == "decimal") return "Decimal" + spl;
            return s + spl;
        }
    }
}